#include <cryptopp/cryptlib.h>
#include <cryptopp/secblock.h>
#include <cryptopp/filters.h>
#include <cryptopp/hc128.h>
#include <cryptopp/osrng.h>
#include <cryptopp/files.h>
#include <cryptopp/hex.h>
#include <iostream>
#include <string>

int main()
{
    using namespace CryptoPP;

    HC128::Encryption enc;
    std::cout << "key length: " << enc.DefaultKeyLength() << std::endl;
    std::cout << "key length (min): " << enc.MinKeyLength () << std::endl;
    std::cout << "key length (max): " << enc.MaxKeyLength () << std::endl;
    std::cout << "iv size: " << enc.IVSize() << std::endl;

    AutoSeededRandomPool prng;
    HexEncoder encoder(new FileSink(std::cout));
    std::string plain("HC-128 stream cipher test111111111111"), cipher, recover;

    SecByteBlock key(16), iv(16);
    prng.GenerateBlock(key, key.size());
    prng.GenerateBlock(iv, iv.size());



    std::cout << std::hex << (int)key.data()[0] << std::endl;
    key.data()[0] = 0xff;
    std::cout << "Key: ";
    encoder.Put(key.data(), key.size());
    encoder.MessageEnd();
    std::cout << std::endl;

    std::string my_key("DE33DAF2860D7228FB8B1D54E2FA34E6");
    char byte_key[16] = {0};
    for (int i = 0; i < 32; i += 2) {
        char t = 0;
        if (my_key[i] > '0' && my_key[i] < '9') {
            t += 16 * (my_key[i] - '0');
        } else {
            t += 16 * (my_key[i] - 'A' + 10);
        }
        if (my_key[i + 1] > '0' && my_key[i + 1] < '9') {
            t += (my_key[i + 1] - '0');
        } else {
            t += (my_key[i + 1] - 'A' + 10);
        }
        byte_key[i / 2] = t;
    }
    for (int i = 0; i < 16; i++) {
        iv.data()[i] = byte_key[i];
    }





    std::cout << "IV: ";
    encoder.Put(iv.data(), iv.size());
    encoder.MessageEnd();
    std::cout << std::endl;

    // Encryption object
    // HC128::Encryption enc;
    enc.SetKeyWithIV(key, key.size(), iv, iv.size());

    // Decryption object
    HC128::Decryption dec;
    dec.SetKeyWithIV(key, key.size(), iv, iv.size());

    StringSource ss1(plain, true, new StreamTransformationFilter(enc, new StringSink(cipher)));
    StringSource ss2(cipher, true, new StreamTransformationFilter(dec, new StringSink(recover)));

    std::cout << "Plain: " << plain << std::endl;

    std::cout << "Cipher: ";
    encoder.Put((const byte*)cipher.data(), cipher.size());
    encoder.MessageEnd();
    std::cout << std::endl;

    std::cout << "Recovered: " << recover << std::endl;

    return 0;
}